#include <sys_config.h>
#include <basic_types.h>
#include <retcode.h>
#include <api/libc/string.h>
#include <osal/osal.h>
#include <bus/sci/sci.h>
#include <hal/hal_gpio.h>
#include <hld/pan/pan_dev.h>
#include <hld/pan/pan.h>
#include <bus/i2c/i2c.h>

#ifndef ARRAY_SIZE
#define ARRAY_SIZE(_array)      (sizeof(_array)/sizeof(_array[0]))
#endif

#ifdef PANEL_DISPLAY

#ifndef FP_CS_GPIO_NUM
#define FP_CS_GPIO_NUM 95
#endif

struct pan_hw_info pan_info =
{
	0,				/* type_kb : 2; Key board (array) type */
	1,				/* type_scan : 1; 0: Slot scan, 1: Shadow scan */
	1,				/* type_key: 1; Key exit or not */
	1,				/* type_irp: 3; 0: not IRP, 1: NEC, 2: LAB */
	0,				/* type_mcu: 1; MCU exit or not */
	4,				/* num_com: 4; Number of com PIN, 0 to 8 */
	1,				/* Position of colon flag, 0 to 7 */
	1,				/* num_scan: 2; Number of scan PIN, 0 to 2 */
	0,				/* rsvd_bits:6; Reserved bits */
	0,              /* rsvd byte for align pan_info */
	{0, HAL_GPIO_O_DIR, FP_CS_GPIO_NUM},		/* LATCH PIN */
	{0, HAL_GPIO_O_DIR, 	FP_CLOCK_GPIO_NUM},		/* CLOCK PIN */
	{1, HAL_GPIO_O_DIR, 	FP_DATA_GPIO_NUM},		/* DATA PIN */
	{{0, HAL_GPIO_I_DIR, 	FP_KEY1_GPIO_NUM},		/* SCAN1 PIN */
	{0, HAL_GPIO_I_DIR, 0x3fff}},		/* SCAN2 PIN */
	{{0, HAL_GPIO_O_DIR, 	FP_COM1_GPIO_NUM},		/* COM1 PIN */
	{0, HAL_GPIO_O_DIR, 	FP_COM2_GPIO_NUM},		/* COM2 PIN */
	{0, HAL_GPIO_O_DIR, 	FP_COM3_GPIO_NUM},		/* COM3 PIN */
	{0, HAL_GPIO_O_DIR, 	FP_COM4_GPIO_NUM},		/* COM4 PIN */
	{0, HAL_GPIO_O_DIR, 0x3fff},		/* COM5 PIN */
	{0, HAL_GPIO_O_DIR, 0x3fff},		/* COM6 PIN */
	{0, HAL_GPIO_O_DIR, 0x3fff},		/* COM7 PIN */
	{0, HAL_GPIO_O_DIR, 0x3fff}},		/* COM8 PIN */
	{{0, HAL_GPIO_O_DIR, 	FP_STANDBY_GPIO_NUM},		/* POWER PIN */
	{1, HAL_GPIO_O_DIR, 	FP_LOCK_GPIO_NUM},		/* LOCK PIN */
	{0, HAL_GPIO_O_DIR, 0x3fff},		/* Extend function LBD */
	{0, HAL_GPIO_O_DIR, 0x3fff}},		/* Extend function LBD */
    {0, HAL_GPIO_O_DIR, 0x3fff},       /* rsvd extend function LBD */
	300,							/* Intv repeat first */
	250,							/* Intv repeat */
	350,							    /* Intv release, 0: disable release key */
	NULL,	 	 	 	 	 	 	/* hook_scan() callback */
	NULL,	 	 	 	 	 	 	/* hook_show() callback */
};
#define bitmap_list				NULL
#define bitmap_list_num		0

struct pan_configuration panel_config = {&pan_info, bitmap_list_num, bitmap_list};
#endif

void sys_uart_init()
{
	if (sci_16550uart_attach(1) == SUCCESS)	// Use just 1 UART for RS232
	{
        libc_printf_uart_id_set(SCI_FOR_RS232);
        sci_mode_set(SCI_FOR_RS232, 115200, SCI_PARITY_EVEN);
    }
}

void sys_gpio_init()
{
#ifdef PANEL_DISPLAY
    UINT32 reg_addr[5] = 
    {
        0xb8000430,  //gpio0 ~ gpio31
        0xb8000434,  //gpio32 ~ gpio63
        0xb8000438,  //gpio64 ~ gpio95
        0xb800043c,  //gpio96 ~ gpio127
        0xb8000440  //gpio128 ~ gpio144
    };
    struct pan_gpio_info bl_gpio_array[3] = {
        {1, HAL_GPIO_O_DIR, 0},
        {1, HAL_GPIO_O_DIR, 0},
        {0, HAL_GPIO_O_DIR, 0}
    };
    struct pan_gpio_info* gpio;
    UINT32 i, j;
    UINT32 value;
    UINT32 i2c_id;

    bl_gpio_array[0].position = SYS_I2C_SDA;
    bl_gpio_array[1].position = SYS_I2C_SCL;
    bl_gpio_array[2].position = 20;     //SMC 5V/3.3V switch
 
    // disable all GPIO
    for(i = 0; i < ARRAY_SIZE(reg_addr); i++)
    {
        value = 0;
        for(j = 0; j < ARRAY_SIZE(bl_gpio_array); j++)
        {
            gpio = &bl_gpio_array[j];
            if(gpio->position >= (i*32) && gpio->position < ((i+1)*32))
                value |= 1 << (gpio->position - (i*32));
        }
        *((volatile unsigned long *)reg_addr[i]) = value;
    }

    for(j = 0; j < ARRAY_SIZE(bl_gpio_array); j++)
    {
         gpio = &bl_gpio_array[j];
         HAL_GPIO_BIT_DIR_SET(gpio->position, gpio->io);
         HAL_GPIO_BIT_SET(gpio->position, gpio->polar);
    }
    
	i2c_scb_attach(2);
	i2c_gpio_attach(3);        

    i2c_gpio_set(I2C_TYPE_GPIO0 & I2C_ID_MASK, bl_gpio_array[0].position, bl_gpio_array[1].position);
    i2c_mode_set(I2C_TYPE_GPIO0, 100000, 1);
#endif
}

void sys_panel_init(void)
{
    UINT32 data;
	UINT32 chip_id;
    struct pan_device *pan_dev;

#ifdef PANEL_DISPLAY
#ifndef C3041
	extern void pan_ch455_id_set(struct pan_device *dev, UINT32 id);
	pan_ch455_attach(&panel_config);
#else
	*((unsigned long *)0xb8000430) |= 3<<8;
	*((unsigned long *)0xb8000434) |= 1<<5;
	pan_sm1668_attach(&panel_config);
#endif

	pan_dev = (struct pan_device *)dev_get_by_id(HLD_DEV_TYPE_PAN, 0);
#ifndef C3041
    pan_ch455_id_set(pan_dev, I2C_TYPE_GPIO0/*I2C_TYPE_SCB1*/);
#endif

    pan_open(pan_dev);
#endif
}

